#include <iostream>
//VSDL headers
#include "VSDL_tools.h"
#include "VSDL_gamengine.h"
#include "VSDL_gamestate.h"
//ULCore headers
#include "ULCore_Serial.h"
#include "ULCore_History.h"
#include "ULCore_Statistic.h"
#include "ULCore_RandomPool.h"
#include "ULCore_Prediction.h"
#include "ULCore_PredictByAC.h"
//ULGfx headers
#include "ULGfx_Serial.h"
#include "ULGfx_History.h"
#include "ULGfx_Statistic.h"
//UI headers
#include "ULUI_MenuList.h"
#include "ULUI_MainMenu.h"
//UL headers
#include "UL_Tools.h"
#include "UL_Global.h"
//Misc headers
#include <SDL/sprig.h>

//Screen resolution
//#define SCREEN_WIDTH		1280
//#define SCREEN_HEIGHT		960
#define SCREEN_WIDTH		1152
#define SCREEN_HEIGHT		864

#define STATISTIC_FONT_SIZE	15
#ifdef __LINUX__
#define STATISTIC_FONT_FILE	"./fonts/uming.ttf"
#else
#define STATISTIC_FONT_FILE	".\\fonts\\uming.ttf"
#endif
//Default file names
#define HISTORY_TXT_FILE	"history.txt"
#define HISTORY_BIN_FILE	"history.bin"
//Balls' images
#define BLUE_BALL_IMAGE_FILE	"./images/blue.png"
#define RED_BALL_IMAGE_FILE	"./images/red.png"
//Misc images
#define BG_IMAGE_FILE		"./images/bg.png"
#define TITLE_IMAGE_FILE	"./images/title.png"
#define PRIZE_IMAGE_FILE	"./images/UL_Prizes.png"



//Message printing
static VSDL_Text msg;
static char msgBuffer[256];
static VSDL_Point msgXY;
int w, h;
//Prediction
static ULC_Prediction prediction;
static ULC_Statistic ulcStat;
//For global use
static VSDL_Font font;
static VSDL_Font statFont;
static VSDL_Image bgImage;
static VSDL_Image titleImage;
static VSDL_Image prizeImage;
static ULG_Balls ulgBalls;
static ULG_Serial ulgSerial;
static ULG_Statistic ulgStat;
static ULG_BallStatistic ulgRedBallStat;
static ULG_BallStatistic ulgBlueBallStat;
static VSDL_GameEngine *game;
static SDL_Surface *screen;

#ifndef __LINUX__
#include <windows.h>
#endif

void UL_Global::UnionLottoUpdateScreen()
{
	SDL_Flip(screen);
	//Debug
#ifdef __LINUX__
	usleep(90000);
#else
	 Sleep(90);
#endif

}

#define UpdateScreen() UL_Global::UnionLottoUpdateScreen()

static void ShowTip(const char *tip)
{
	msg.SetText(tip);
	msg.Blit(screen, msgXY);
	UpdateScreen();
	msgXY.y += h;
}

void UL_Global::UnionLottoShowTip(const char *tip, VSDL_Point point)
{
	if (tip != NULL){
		msg.SetText(tip);
		msg.Blit(screen, point);
	}
}

void UL_Global::UnionLottoSetTipColor(VSDL_RGB rgb)
{
	msg.SetFgColor(rgb.r, rgb.g, rgb.b);
}

int UL_Global::UnionLottoGetFontHeight()
{
	return h;
}

int UL_Global::UnionLottoInit(bool updateHistoryData, const char *fontFileName, int fontSize, const char *binHistoryFile, unsigned int random_seed)
{
	ULG_History *historyData;
	int ret;

	//Init random seed
	if (random_seed != 0){
		VSDL_Tool::Srand(random_seed);
	}

	game = new VSDL_GameEngine(SCREEN_WIDTH, SCREEN_HEIGHT, "Union Lotto Analyser - liuliang v1.0.0", 24, false);
	
	if (game == NULL){
		cerr << "Fatal error: cannot init engine" << endl;
		return -1;
	}

	screen = game->GetSurface();

	if (screen == NULL){
		cerr << "Fatal error: cannot init screen" << endl;
		return -1;
	}

	game->FillScreen(VSDL_RGB(0, 0, 0));
	UpdateScreen();

	if (fontSize <= 0 || font.LoadFont(fontFileName, fontSize) < 0 || statFont.LoadFont(STATISTIC_FONT_FILE, STATISTIC_FONT_SIZE) < 0 ){
		cerr << "Fatal error: cannot init font" << endl;
		return -1;
	}	

	if (binHistoryFile == NULL){
		binHistoryFile = HISTORY_BIN_FILE;
	}

	msg.SetFont(&font);
	msg.SetEncode(FONT_CODE_UTF8);
	msg.SetFgColor(80, 200, 80);

	msgXY.x = 0;
	msgXY.y = 50;
	msg.SetText("Loading images for balls...");
	msg.Blit(screen, msgXY);
	msg.GetTextSize(&w, &h);
	msgXY.y += h;
	UpdateScreen();

	if (ulgBalls.LoadImageFiles(RED_BALL_IMAGE_FILE, VSDL_RGB(0, 0, 0), BLUE_BALL_IMAGE_FILE, VSDL_RGB(0, 0, 0)) < 0 ){
		ShowTip("Failed to load images(Files existed?), exiting...");
#ifdef __LINUX__
		sleep(1);
#else
	 	Sleep(1000);
#endif
		exit(-1);
	}

	ulgBalls.SetBallNumberFont(&font);
	ulgSerial.SetTipFont(&font);
	ulgSerial.SetULGBalls(&ulgBalls);
	ulgStat.SetFont(&statFont);
	ulgRedBallStat.SetULGBall(&ulgBalls.redBall);
	ulgBlueBallStat.SetULGBall(&ulgBalls.blueBall);

	//Tips - Loading history data
	ShowTip("Loading history data...");

	historyData = ULG_History::Instance();
	
	if (updateHistoryData){
		ShowTip("Getting history data file from internet...");

		ret = UL_Tools::GetHistoryFileFromWebSite(HISTORY_TXT_FILE);
		if (ret < 0){
			ShowTip("Failed to get history file from internet, use default file");
		}else{
			  if (UL_Tools::FileExists(binHistoryFile)){
			  	 ShowTip("History file retrieved from internet.");
			  	 ShowTip("Updating binary history file...");
				 historyData->UpdateBinHistory(HISTORY_TXT_FILE, binHistoryFile);
 			 }else{
	  		 	   ShowTip("Generating binary history file...");
	  		 	   historyData->GenerateBinHistory(HISTORY_TXT_FILE, binHistoryFile);
#ifdef __LINUX__
	   			   sleep(1);
#else
	 			   Sleep(1000);
#endif
			 }
		}
	}

	sprintf(msgBuffer, "Parsing history data from binary file %s...", binHistoryFile);
	ShowTip(msgBuffer);
	
	if ( historyData->ParseBinHistory(binHistoryFile) < 0 ){
		ShowTip("Failed to parse binary history data file, exiting...");
#ifdef __LINUX__
		sleep(1);
#else
	 	Sleep(1000);
#endif
		exit(-1);
	}

	ShowTip("Initializing global data...");

	historyData->SetFont(&font);
	historyData->SetULGSerial(&ulgSerial);
	ulcStat.ParseHistoryData(*historyData);
	prediction.ParseStatistic(ulcStat);

	ShowTip("Loading background image...");
	
	if (bgImage.LoadImage(BG_IMAGE_FILE) < 0){
		ShowTip("Failed to load background image, no background can be shown");
	}

	ShowTip("Loading title image...");

	if (titleImage.LoadImage(TITLE_IMAGE_FILE) < 0){
		ShowTip("Failed to load title image, no title can be shown");
	}

	ShowTip("Loading prize image...");

	if (prizeImage.LoadImage(PRIZE_IMAGE_FILE) < 0){
		ShowTip("Failed to load prize image, no prize help image can be shown");
	}

	ShowTip("All subsystem initialized.");
	
	msg.SetFgColor(0, 0, 0);
	return 0;
}

void UL_Global::UnionLottoRun()
{
	game->PushState(ULUI_MainMenu::Instance());

	game->Run();
}

void UL_Global::UnionLottoEnd()
{
	game->End();
}

VSDL_Font *UL_Global::UnionLottoFont()
{
	return &font;
}

ULG_Ball *UL_Global::UnionLottoRedBall()
{
	return &ulgBalls.redBall;
}

ULG_Ball *UL_Global::UnionLottoBlueBall()
{
	return &ulgBalls.blueBall;
}

ULG_Balls *UL_Global::UnionLottoBalls()
{
	return &ulgBalls;
}

ULG_Serial *UL_Global::UnionLottoSerial()
{
	return &ulgSerial;
}

ULG_Statistic *UL_Global::UnionLottoStatistic()
{
	return &ulgStat;
}

ULG_BallStatistic *UL_Global::UnionLottoBallStatistic(bool red)
{
	if (red){
		return &ulgRedBallStat;
	}else{
		return &ulgBlueBallStat;
	}
}

ULC_Statistic *UL_Global::UnionLottoTotalStatistic()
{
	return &ulcStat;
}

void UL_Global::UnionLottoShowTitle()
{
	VSDL_RGB rgb;
	float radius;
	int i;

	msgXY.x = msgXY.y = 0;

	titleImage.Blit(screen, 0, 0);
	//Draw red rect
	rgb.SetRGB(250, 80, 80);
	SPG_RectFilled(screen, 100, 0, screen->w, 50, rgb.GetRGB32(screen));
	SPG_RectFilled(screen, 0, 100, 50, screen->h, rgb.GetRGB32(screen));
	//Draw blue rect
	rgb.SetRGB(80, 80, 250);
	SPG_RectFilled(screen, 100, 50, screen->w, 90, rgb.GetRGB32(screen));
	SPG_RectFilled(screen, 50, 100, 90, screen->h, rgb.GetRGB32(screen));
	//Draw red circles
	rgb.SetRGB(250, 80, 80);
	for (radius = 50.1f; radius <= 60.1f; radius += 1.0f){
		SPG_Circle(screen, 50, 50, radius, rgb.GetRGB32(screen));
	}
	//Draw blue circles
	rgb.SetRGB(80, 80, 250);
	for (radius = 60.1f; radius <= 70.1f; radius += 1.0f){
		SPG_Circle(screen, 50, 50, radius, rgb.GetRGB32(screen));
	}

}

void UL_Global::UnionLottoShowBg()
{
	bgImage.Blit(screen, 0, 0);
}

void UL_Global::UnionLottoShowPrizeTable(VSDL_Point point)
{
	prizeImage.Blit(screen, point);
}

void UL_Global::UnionLottoPredictFullyRandom(ULC_Serial &serial)
{
	prediction.PredictNextSerialByRandom(serial);
}

void UnionLottoPredictByBlue(ULC_Serial &serial, int blue)
{

}

void UL_Global::UnionLottoPredictByAC(ULC_Serial &serial)
{
	ULC_PredictByAC predAC;

	predAC.PredictNextSerial(serial, *ULG_History::Instance());
}
